package com.thunder.reader.ui;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ImageSpan;
import android.text.util.Linkify;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.thunder.reader.FeedSettings;
import com.thunder.reader.R;
import com.thunder.reader.html.HtmlSimpleParser;
import com.thunder.reader.provider.Feed;
import com.thunder.reader.util.Utility;
import com.thunder.reader.weibo.Share2WeiboActivity;

public class ViewArticleActivity extends Activity {
    protected static final String TAG = FeedSettings.GLOBAL_TAG;
    public static final String EXTRA_ARTICLE_URL = "article_url";
    public static final String EXTRA_CURRENT_POSITION = "current_position";
    public static final String EXTRA_SOURCE_ID = "source_id";
    
    private static final int TOKEN_QUERY_ALL_ARTICLE = 0;
    private static final int TOKEN_QUERY_THIS_ARTICLE = 1;
    
    private AsyncArticleQueryHandler mQueryHandler;
    private Uri mArticleUri;
    private int mCurrentPosition;
    private int mSourceId;
    private Cursor mArticleCursor;
    private Cursor mArticleListCursor;
    private TextView mArticleHeader;
    private ScrollView mScroller;
    private LinearLayout mContainer;
    
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        final Intent intent = getIntent();
        if (intent == null) {
            Log.e(TAG, "what the heck, intent is null");
            Toast.makeText(getApplication(), "Unknown error happend", Toast.LENGTH_SHORT).show();
            finish();
            setTransitionAnimation();
        }
        mArticleUri = intent.getData();
        if (mArticleUri == null) {
            Log.e(TAG, "what the heck article uri is null");
            Toast.makeText(getApplication(), "Unknown error happend", Toast.LENGTH_SHORT).show();
            finish();
            setTransitionAnimation();
        }
        mCurrentPosition = intent.getIntExtra(EXTRA_CURRENT_POSITION, 0);
        mSourceId = intent.getIntExtra(EXTRA_SOURCE_ID, -1);
        setContentView(R.layout.view_article);
        mArticleHeader = (TextView) findViewById(R.id.article_header);
        mScroller = (ScrollView) findViewById(R.id.scroll_view);
        mScroller.setOnTouchListener(new View.OnTouchListener() {
	    @Override
	    public boolean onTouch(View v, MotionEvent event) {
		mTransitionGestureDector.onTouchEvent(event);
		return false;
	    }
	});
        mContainer = (LinearLayout) findViewById(R.id.container);
        mQueryHandler = new AsyncArticleQueryHandler(getContentResolver());
        startAsyncQuery(mSourceId);
    }

    private void showArticle() {
        final String title = mArticleCursor.getString(Feed.Article.TITLE_INDEX);
        final String pubdate = Utility.dateToString(mArticleCursor.getLong(Feed.Article.PUB_DATE_INDEX));
        final String content = mArticleCursor.getString(Feed.Article.CONTENT_INDEX);
        final SpannableStringBuilder header = new SpannableStringBuilder();
        header.append(title);
        int start = 0;
        int end = title.length();
        header.setSpan(new AbsoluteSizeSpan(22), start, end, 0);
        start = end + 1;
        end += pubdate.length() + 1;
        header.append("\n");
        header.append(pubdate);
        header.setSpan(new AbsoluteSizeSpan(16), start, end, 0);
        mArticleHeader.setText(header);
        final List parts = HtmlSimpleParser.fromHtml(content);
        for (Object obj : parts) {
            if (obj instanceof ImageSpan) {
                final ReaderImageView image = new ReaderImageView(getApplication());
                ImageSpan i = (ImageSpan) obj;
                new ImageDownloader(image).execute(i.getSource());
                mContainer.addView(image);
            } else {
                // add an text string
                final TextView text = new TextView(getApplication());
                text.setText((Spanned) obj);
                final int padding = getDensityLength(10);
                text.setPadding(padding, 0, padding, padding);
                text.setTextColor(Color.BLACK);
                text.setAutoLinkMask(Linkify.ALL);
                mContainer.addView(text);
            }
        }
    }

    private GestureDetector mTransitionGestureDector = new GestureDetector(new TransitionGestureListener());
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.view_article, menu);
        return true;
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // NOTE: cursor.moveToNext() and cursor.moveToPrevious() are not reliable
        menu.findItem(R.id.view_article_previous).setEnabled(mCurrentPosition > 0);
        menu.findItem(R.id.view_article_next).setEnabled(mCurrentPosition < getArticleCount());
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.view_article_view_original: {
            final Intent intent = new Intent(getApplication(), ViewOriginalArticleActivity.class);
            intent.setData(mArticleUri);
            startActivity(intent);
            overridePendingTransition(R.anim.default_come_enter, R.anim.default_come_exit);
            break;
        }
        case R.id.view_article_next: {
            showNextArticle();
            break;
        }
        case R.id.view_article_previous: {
            showPreviousArticle();
            break;
        }
        case R.id.view_article_share:
            final Intent intent = new Intent(getApplication(), Share2WeiboActivity.class);
            intent.putExtra(Share2WeiboActivity.EXTRA_MESSAGE_TEXT, mArticleCursor.getString(Feed.Article.TITLE_INDEX));
            intent.putExtra(Share2WeiboActivity.EXTRA_MESSAGE_URL, mArticleCursor.getString(Feed.Article.ARTICLE_URL_INDEX));
            intent.putExtra(Share2WeiboActivity.EXTRA_IMAGE_TO_SHARE, getImagePath());
            startActivity(intent);
            overridePendingTransition(R.anim.share2weibo_come_enter, R.anim.share2weibo_come_exit);
            break;
        default:
            break;
        }
        return true;
    }

    @Override
    protected void onDestroy() {
	if (mArticleCursor != null) {
	    mArticleCursor.close();
	}
	if (mArticleListCursor != null) {
	    mArticleListCursor.close();
	}
	super.onDestroy();
    }

    @Override
    public void onBackPressed() {
	super.onBackPressed();
	setTransitionAnimation();
    }

    private void setTransitionAnimation() {
	overridePendingTransition(R.anim.default_leave_enter, R.anim.default_leave_exit);
    }
    
    private String getImagePath() {
        String path = null;
        final long imageId = mArticleCursor.getLong(Feed.Article.IMAGE_ID_INDEX);
        final Uri uri = ContentUris.withAppendedId(Feed.Image.CONTENT_URI, imageId);
        final Cursor cursor = getContentResolver().query(uri, new String[]{Feed.Image._DATA}, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            path = cursor.getString(0);
        }
        if (cursor != null) {
            cursor.close();
        }
        return path;
    }

    private void showPreviousArticle() {
        if (mArticleListCursor != null) {
            mCurrentPosition--;
            showCurrentArticle();
            overridePendingTransition(R.anim.prev_article_enter, R.anim.prev_article_exit);
        }
    }

    private void showNextArticle() {
        if (mArticleListCursor != null) {
            mCurrentPosition++;
            showCurrentArticle();
            overridePendingTransition(R.anim.next_article_enter, R.anim.next_article_exit);
        }
    }

    private void showCurrentArticle() {
	mArticleListCursor.moveToPosition(mCurrentPosition);
	final int id = mArticleListCursor.getInt(0);
	mArticleUri = ContentUris.withAppendedId(Feed.Article.CONTENT_URI, id);
        final ContentValues cv = new ContentValues();
        cv.put(Feed.Article.READ, 1);
        getContentResolver().update(mArticleUri, cv, null, null);
        final Intent intent = createViewArticleIntent(getApplication(), mArticleUri, mCurrentPosition, mSourceId);
        startActivity(intent);
        finish();
    }

    public static Intent createViewArticleIntent(Context context, Uri articleUri, int currentPosition, int sourceId) {
	final Intent intent = new Intent(context, ViewArticleActivity.class);
        intent.setData(articleUri);
        intent.putExtra(EXTRA_CURRENT_POSITION, currentPosition);
        intent.putExtra(EXTRA_SOURCE_ID, sourceId);
	return intent;
    }
    
    private int getArticleCount() {
        return mArticleListCursor == null ? 0 : mArticleListCursor.getCount() - 1;
    }
    
    private int getDensityLength(int len) {
	final float density = getApplication().getResources().getDisplayMetrics().density;
	return (int) (density * len);
    }
    
    private void startAsyncQuery(int sourceId) {
	mQueryHandler.startQuery(TOKEN_QUERY_THIS_ARTICLE, null, 
		mArticleUri, Feed.Article.PROJECTION, null, null, null);
	mQueryHandler.startQuery(TOKEN_QUERY_ALL_ARTICLE, null, 
		Feed.Article.CONTENT_URI, new String[]{Feed.Article._ID}, Feed.Article.SOURCE_ID + "=?", 
		new String[]{String.valueOf(sourceId)}, "pub_date DESC");
    }
    
    private final class AsyncArticleQueryHandler extends AsyncQueryHandler {
        public AsyncArticleQueryHandler(ContentResolver cr) {
            super(cr);
        }
        
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            switch (token) {
            case TOKEN_QUERY_ALL_ARTICLE:
        	mArticleListCursor = cursor;
        	if (mArticleListCursor != null) {
        	    mArticleListCursor.moveToPosition(mCurrentPosition);
        	}
        	break;
            case TOKEN_QUERY_THIS_ARTICLE:
        	mArticleCursor = cursor;
        	if (mArticleCursor != null && mArticleCursor.moveToFirst()) {
        	    showArticle();
        	}
        	break;
            default:
        	break;
            }
        }
        
        @Override
        protected void onDeleteComplete(int token, Object cookie, int result) {
            
        }
        
        @Override
        protected void onUpdateComplete(int token, Object cookie, int result) {
            
        }
        
        @Override
        protected void onInsertComplete(int token, Object cookie, Uri uri) {
            
        }
    }

    private class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
        private final ReaderImageView mDisplay;
        
        public ImageDownloader(final ReaderImageView display) {
            mDisplay = display;
        }

        
        @Override
        protected void onPreExecute() {
            mDisplay.setImageResource(R.drawable.icon);
            final int margin = getDensityLength(10);
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.setMargins(margin, 0, margin, margin);
            mDisplay.setLayoutParams(params);
            mDisplay.setScaleType(ScaleType.CENTER);
        }
        
        @Override
        protected Bitmap doInBackground(String... url) {
            URL u;
            Bitmap bm = null;
            try {
                if (isCancelled()) {
                    return null;
                }
                u = new URL(url[0]);
                final HttpURLConnection conn = (HttpURLConnection) u.openConnection();
                if (isCancelled()) {
                    return null;
                }
                conn.setDoInput(true);
                conn.setDoOutput(false);
                conn.setConnectTimeout(FeedSettings.getConnectionTimeout());
                if (isCancelled()) {
                    return null;
                }
                if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    Log.e(TAG, "Not okay: code " + conn.getResponseCode() + ", msg " + conn.getResponseMessage());
                    return null;
                }
                if (isCancelled()) {
                    return null;
                }
                final InputStream in = conn.getInputStream();
                if (isCancelled()) {
                    return null;
                }
                bm = BitmapFactory.decodeStream(in);
            } catch (MalformedURLException e) {
                Log.e(TAG, "exception caught " + e.getMessage());
            } catch (IOException e) {
                Log.e(TAG, "exception caught " + e.getMessage());
            }
            return bm;
        }

        @Override
        protected void onPostExecute(Bitmap bm) {
            if (bm != null) {
                mDisplay.setImageBitmap(bm);
            }
        }
    }
    
    private class ReaderImageView extends ImageView {
        private Bitmap mBitmap;
        public ReaderImageView(Context context) {
            super(context);
        }

        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            setLayoutParams();
        }

        @Override
        public void setImageBitmap(Bitmap bm) {
            mBitmap = bm;
            setLayoutParams();
            super.setImageBitmap(bm);
        }

        private void setLayoutParams() {
            if (mBitmap == null) {
                return;
            }
            final DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            final int margin = getDensityLength(10);
            final int screenWidth = dm.widthPixels - margin * 2;
            final int width = mBitmap.getWidth();
            final int height = mBitmap.getHeight();
            final int screenHeight = (int) ((float) screenWidth * height / (float) width);
            LayoutParams params = null;
            if (width > screenWidth) {
                params = new LayoutParams(screenWidth, screenHeight);
            } else {
                params = new LayoutParams(width, height);
            }
            params.setMargins(margin, 0, margin, margin);
            setLayoutParams(params);
            setScaleType(ScaleType.FIT_XY);
        }
    }

    private class TransitionGestureListener extends SimpleOnGestureListener {
        private boolean mGestureRecognized;
        private Toast mEndNotification;
        private Toast mHeadNotification;

        public TransitionGestureListener() {
            mGestureRecognized = false;
        }

        @Override
        public boolean onDown(MotionEvent e) {
            if (mGestureRecognized) {
                return true;
            }
            return super.onDown(e);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (mGestureRecognized) {
                return true;
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (mGestureRecognized) {
                return true;
            }
            if (distanceY*distanceY > distanceX*distanceX) {
                return false;
            }
            if (distanceX > 10 && distanceY < 5) {
                if (mCurrentPosition < getArticleCount()) {
                    mGestureRecognized = true;
                    showNextArticle();
                    return true;
                } else {
                    if (mEndNotification == null) {
                        mEndNotification = Toast.makeText(getApplication(), "No more articles", Toast.LENGTH_SHORT);
                    }
                    mEndNotification.show();
                }
            }
            if (distanceX < -10 && distanceY < 5) {
                if (mCurrentPosition > 0) {
                    mGestureRecognized = true;
                    showPreviousArticle();
                    return true;
                } else {
                    if (mHeadNotification == null) {
                        mHeadNotification = 
                            Toast.makeText(getApplication(), "This is the first article", Toast.LENGTH_SHORT);
                    }
                    mHeadNotification.show();
                }
            }
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }
}